package com.bsb.biz.service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import com.bsb.base.common.config.Global;
import com.bsb.base.common.util.StringUtils;
import com.bsb.base.common.util.wx.Sha1Util;
import com.bsb.base.common.util.wx.WxPayResultNotify;
import com.bsb.base.common.util.wx.mapUtil;
import com.bsb.base.model.WxPayReq;
import com.bsb.base.model.WxQueryOrderRes;
import com.bsb.biz.service.callback.BaseWxPayCallback;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest;
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest;
import me.chanjar.weixin.mp.bean.pay.result.WxEntPayResult;
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderQueryResult;

@Service
public class PaymentService implements ApplicationContextAware {
	private static final Logger logger = Logger.getLogger(PaymentService.class);

	@Resource(name = "wxAppService")
	private WxMpService wxAppService;

	private ApplicationContext applicationContext;

	/**
	 * 调用微信统一下单接口
	 * 
	 * @param map
	 * @return <return_msg><![CDATA[OK]]></return_msg>
	 *         <appid><![CDATA[wx64eaa52e2ff9ec97]]></appid>
	 *         <mch_id><![CDATA[1358458902]]></mch_id>
	 *         <nonce_str><![CDATA[CZLWm9BgpDgwATGU]]></nonce_str>
	 *         <sign><![CDATA[E057DE733DAE8DA622FFDCDE7CF5235A]]></sign>
	 *         <result_code><![CDATA[SUCCESS]]></result_code>
	 *         <prepay_id><![CDATA[wx20170407161518dee49f84ac0310755272]]></prepay_id>
	 *         <trade_type><![CDATA[NATIVE]]></trade_type>
	 *         <code_url><![CDATA[weixin://wxpay/bizpayurl?pr=FvRlkl0]]></code_url>
	 *         </xml>
	 * @throws WxErrorException
	 */
	private Map<String, String> getPayinfo(Map<String, String> map) throws WxErrorException {
		WxPayUnifiedOrderRequest payInfo = new WxPayUnifiedOrderRequest();
		payInfo.setBody(map.get("body"));
		payInfo.setTradeType(map.get("trade_type"));
		payInfo.setNotifyURL(map.get("notify_url"));
		payInfo.setAttach(map.get("attach"));
		payInfo.setDeviceInfo(map.get("device_info"));
		payInfo.setGoodsTag(map.get("goods_tag"));
		payInfo.setLimitPay(map.get("limit_pay")); // 指定支付方式
		payInfo.setNonceStr(map.get("nonce_str"));
		payInfo.setOpenid(map.get("openid"));
		payInfo.setOutTradeNo(map.get("out_trade_no"));
		payInfo.setProductId(map.get("product_id"));
		payInfo.setSign(map.get("sign"));
		payInfo.setSpbillCreateIp(map.get("spbill_create_ip"));
		payInfo.setTimeExpire(map.get("time_expire"));
		payInfo.setTimeStart(map.get("time_start"));
		BigDecimal amont = new BigDecimal(map.get("total_fee"));
		payInfo.setTotalFee(amont.multiply(new BigDecimal(100)).intValue());
		logger.info("微信支付请求报文:" + payInfo);
		// 没有二次加密
		// WxPayUnifiedOrderResult unifiedOrder =
		// this.wxMpService.getPayService().unifiedOrder(payInfo);
		// 经过二次加密
		Map<String, String> payInfo2 = this.wxAppService.getPayService().getPayInfo(payInfo);
		return payInfo2;
	}

	/**
	 * 组装扫码支付所需参数
	 * 
	 * @return
	 */
	public Map<String, String> qrCodePayParam(Map<String, String> params) {
		String body = params.get("body");
		String out_trade_no = params.get("out_trade_no");
		String total_fee = params.get("total_fee");
		String spbill_create_ip = params.get("spbill_create_ip");
		String notify_url = params.get("notify_url");
		String product_id = params.get("product_id");
		String attach = params.get("attach");

		Map<String, String> map = new HashMap<String, String>();
		map.put("nonce_str", Sha1Util.getNonceStr());
		map.put("body", body);
		map.put("out_trade_no", out_trade_no);
		map.put("total_fee", total_fee);
		map.put("spbill_create_ip", spbill_create_ip);
		map.put("notify_url", notify_url);
		map.put("trade_type", "NATIVE");
		map.put("product_id", product_id);
		map.put("attach", attach);
		map.put("sign", this.wxAppService.getPayService().createSign(map,
				this.wxAppService.getWxMpConfigStorage().getPartnerKey()));
		return map;
	}

	/**
	 * 组装jsapi支付所需参数
	 * 
	 * @param params
	 * @return
	 */
	public Map<String, String> jsPayParam(Map<String, String> params) {
		String body = params.get("body");
		String out_trade_no = params.get("out_trade_no");
		String total_fee = params.get("total_fee");
		String spbill_create_ip = params.get("spbill_create_ip");
		String notify_url = params.get("notify_url");
		String product_id = params.get("product_id");
		String attach = params.get("attach");
		String openid = params.get("openid");

		Map<String, String> map = new HashMap<String, String>();
		map.put("nonce_str", Sha1Util.getNonceStr());
		map.put("body", body);
		map.put("out_trade_no", out_trade_no);
		map.put("total_fee", total_fee);
		map.put("spbill_create_ip", spbill_create_ip);
		map.put("notify_url", notify_url);
		map.put("trade_type", "JSAPI");
		map.put("product_id", product_id);
		map.put("attach", attach);
		map.put("openid", openid);
		map.put("sign", this.wxAppService.getPayService().createSign(map,
				this.wxAppService.getWxMpConfigStorage().getPartnerKey()));
		return map;
	}

	/**
	 * 调用扫码支付
	 * 
	 * @param params
	 * @param callback
	 * @return
	 * @throws WxErrorException
	 */
	public Map<String, String> qrCodePay(WxPayReq req, BaseWxPayCallback callback) throws WxErrorException {
		String productId = req.getProductId();
		String out_trade_no = req.getOut_trade_no();
		String ip = req.getIp();
		// long total_fee = req.getTotal_fee();
		long total_fee = 1;
		String simpleName = callback.getClass().getSimpleName();
		Map<String, Object> attachMap = new HashMap<String, Object>();
		String lowerCaseFirstOne = StringUtils.toLowerCaseFirstOne(simpleName);
		attachMap.put("callback", lowerCaseFirstOne);

		Map<String, String> map = new HashMap<String, String>();
		map.put("body", "解税宝会员卡续费");
		map.put("out_trade_no", out_trade_no);
		map.put("total_fee", String.valueOf(total_fee));
		map.put("spbill_create_ip", ip);
		map.put("notify_url", "");
		map.put("product_id", productId);
		map.put("attach", attachMap.toString());
		Map<String, String> qrCodePayParam = qrCodePayParam(map);
		Map<String, String> payinfo = getPayinfo(qrCodePayParam);
		logger.warn(payinfo);

		return payinfo;
	}

	/**
	 * 公众号支付
	 * 
	 * @param params
	 * @param callback
	 * @return
	 * @throws WxErrorException
	 */
	public Map<String, String> jsPay(WxPayReq req, BaseWxPayCallback callback) throws WxErrorException {
		String productId = req.getProductId();
		String out_trade_no = req.getOut_trade_no();
		String ip = req.getIp();
		String openid = req.getOpenid();
		long total_fee = req.getTotal_fee();
		// long total_fee = 1;
		String simpleName = callback.getClass().getSimpleName();
		Map<String, Object> attachMap = new HashMap<String, Object>();
		String lowerCaseFirstOne = StringUtils.toLowerCaseFirstOne(simpleName);
		attachMap.put("callback", lowerCaseFirstOne);

		Map<String, String> map = new HashMap<String, String>();
		map.put("openid", openid);
		map.put("body", "购买会员卡");
		map.put("out_trade_no", out_trade_no);
		map.put("total_fee", String.valueOf(total_fee));
		map.put("spbill_create_ip", ip);
		map.put("notify_url", "");
		map.put("product_id", productId);
		map.put("attach", attachMap.toString());
		Map<String, String> qrCodePayParam = jsPayParam(map);
		Map<String, String> payinfo = getPayinfo(qrCodePayParam);
		logger.warn(payinfo);

		return payinfo;
	}

	public void afterPaySuc(Map<String, Object> kvm) throws Exception {
		WxPayResultNotify notify = (WxPayResultNotify) mapUtil.mapToBean(kvm, WxPayResultNotify.class);
		// // String sign = map.get("sign");
		// String openid = notify.getOpenid();
		// Double total_fee = Double.valueOf(notify.getTotal_fee());
		// total_fee = total_fee / 100;
		// Date time_end = DateUtils.parseDate(notify.getTime_end());
		// logger.warn("微信回调中返回的成功时间：" + time_end);
		String attach = notify.getAttach();
		logger.info("附加参数值：" + attach);
		Map<String, String> strToMap = mapUtil.strToMap(attach);
		try {
			String callbackKey = (String) strToMap.get("callback");
			logger.info("回调实现类的key：" + callbackKey);
			// 根据key获取对应实现类
			// BaseWxPayCallback callback =
			// AnnotationScannerConfigurer.getCallback(callbackKey);
			BaseWxPayCallback callback = (BaseWxPayCallback) applicationContext.getBean(callbackKey);
			callback.onSuccess(notify);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	/**
	 * 查询订单
	 * 
	 * @param partner_trade_no
	 * @return
	 */
	public WxQueryOrderRes queryOrder(String partner_trade_no) {
		WxQueryOrderRes res = new WxQueryOrderRes();
		WxPayOrderQueryResult queryOrder = null;
		try {
			queryOrder = this.wxAppService.getPayService().queryOrder("", partner_trade_no);
			if (null != queryOrder) {
				String returnCode = queryOrder.getReturnCode();
				String returnMsg = queryOrder.getReturnMsg();
				String resultCode = queryOrder.getResultCode();
				String tradeState = queryOrder.getTradeState();
				if (returnCode.equalsIgnoreCase(Global.SUCCESS)) {
					if (resultCode.equalsIgnoreCase(Global.SUCCESS)) {
						if (tradeState.equalsIgnoreCase(Global.SUCCESS)) {
							res.setCode(Global.YES);
							res.setDes("支付成功");
						} else if (tradeState.equalsIgnoreCase("REFUND")) {
							res.setCode(WxQueryOrderRes.REFUND);
							res.setDes("转入退款");
						} else if (tradeState.equalsIgnoreCase("NOTPAY")) {
							res.setCode(WxQueryOrderRes.NOTPAY);
							res.setDes("未支付");
						} else if (tradeState.equalsIgnoreCase("CLOSED")) {
							res.setCode(WxQueryOrderRes.CLOSED);
							res.setDes("已关闭");
						} else if (tradeState.equalsIgnoreCase("REVOKED")) {
							res.setCode(WxQueryOrderRes.REVOKED);
							res.setDes("已撤销（刷卡支付）");
						} else if (tradeState.equalsIgnoreCase("USERPAYING")) {
							res.setCode(WxQueryOrderRes.USERPAYING);
							res.setDes("用户支付中");
						} else if (tradeState.equalsIgnoreCase("PAYERROR")) {
							res.setCode(WxQueryOrderRes.PAYERROR);
							res.setDes("支付失败(其他原因，如银行返回失败)");
						}
						return res;
					} else {
						String errCode = queryOrder.getErrCode();
						String errCodeDes = queryOrder.getErrCodeDes();
						logger.error("调用微信支付查询订单接口：err_code:" + errCode + ",err_code_des:" + errCodeDes);
						res.setCode(Global.NO);
						res.setDes("系统繁忙");
					}
				} else {
					logger.error("微信支付查询订单接口通信异常resultCode:" + resultCode + ",returnMsg:" + returnMsg);
					res.setCode(Global.NO);
					res.setDes("系统繁忙");
				}
			} else {
				res.setCode(Global.NO);
				res.setDes("系统繁忙");
			}
		} catch (WxErrorException e) {
			e.printStackTrace();
			logger.error("微信支付查询订单接口通信异常:" + e.getMessage().toString());
			res.setCode(Global.NO);
			res.setDes("系统繁忙");
		}
		return res;
	}

	public WxEntPayResult entPay(String tradeNo, String openid, double money, String ip) throws Exception {
		// money = 1.0;
		BigDecimal amont = new BigDecimal(money);
		WxEntPayRequest request = new WxEntPayRequest();
		request.setAmount(amont.multiply(new BigDecimal(100)).intValue());
		request.setCheckName("NO_CHECK");
		request.setDescription("办税宝微信提现");
		request.setOpenid(openid);
		request.setSpbillCreateIp(ip);
		request.setPartnerTradeNo(tradeNo);
		WxEntPayResult entPay = null;
		this.wxAppService.getWxMpConfigStorage().setSslContextFilePath(Global.getConfig("wx.keyPath"));
		entPay = this.wxAppService.getPayService().entPay(request);

		return entPay;
	}

}
